/***************************************************************************
 *            object_3d.c
 *
 *  Mon Aug 25 17:40:14 2008
 *  Copyright  2008  Tiago Falcão
 *  <tiago@tiagofalcao.com>
 ****************************************************************************/

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Library General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
 */
#include "object.h"
#include "screen.h"

// Cria Objeto 3D
object * object_create(void (*display)(void *,bool,GLuint), void * o,void (*object_delete)(void *)){
	object * obj= calloc(1,sizeof(object));
	obj->display=display;							//Funcao de Display
	obj->object=o;									//Ponteiro de Estrutura do Objeto
	obj->object_delete=object_delete;				//Funcao de Delete do Objeto
	
	obj->color[0]=1.;
	obj->color[1]=1.;
	obj->color[2]=1.;
	obj->color[3]=1.;
	
	obj->matrix=matrix_create();					//Cria Matriz de Transformacao do Objeto
	
	return obj;										//Retorna Objeto
}

//Libera Objeto 3D
void object_delete(object * obj){
	matrix_delete(obj->matrix);						//Libera Matriz
	obj->object_delete(obj->object);				//Deleta Estrutura de Dados do Objeto
	free(obj);										//Deleta Objeto
}

// Desenha Objeto 3D
void object_display(object * obj){
	GLfloat bkp=obj->color[3];
	glPushMatrix ();
	//Transformação
	glMultMatrixf(obj->matrix);
	//Cor
	if(objs->selected && !(obj->mode&OBJ3D_MODE_SELECTED))
		obj->color[3]=.2;
	glColor4fv(obj->color);
	//Brilho
	glMaterialfv(GL_FRONT, GL_AMBIENT, obj->ambient);		//Ambiente
	glMaterialfv(GL_FRONT, GL_DIFFUSE, obj->diffuse);		//Difusao
	glMaterialfv(GL_FRONT, GL_SPECULAR, obj->specular);		//Reflexao
	glMaterialf(GL_FRONT, GL_SHININESS, obj->shininess);	//Concentracao
	glMaterialfv(GL_FRONT, GL_EMISSION, obj->emission);	 	//Emissao
	//Desenho do Objeto
	object_display_mode(obj);
	
	obj->color[3]=bkp;
	glPopMatrix ();
}

void object_display_mode(object * o){
	int mode=o->mode;
	
	if(!(mode&(~OBJ3D_MODE_SELECTED)))										//Sem Modo?
		mode|=OBJ3D_MODE_FILL | OBJ3D_MODE_SMOOTH;
	
	if(mode & OBJ3D_MODE_FACE){					//Modo Face;
		GLfloat colorline[4];						//Cor da Silhueta
		colorline[0]=1.;//1.- o->color[0];
		colorline[1]=0.;//1.- o->color[1];
		colorline[2]=0.;//1.- o->color[2];
		colorline[3]=o->color[3];
		//printf("%f %f %f %f\n",colorline[0],colorline[1],colorline[2],colorline[3]);
		glColor4fv(colorline);
		
		glLineWidth(2.0);
		glDisable(GL_LIGHTING);
		glEnable(GL_CULL_FACE);
		glCullFace(GL_FRONT);
		glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
		o->display(o->object,false,0);
		
		
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
		glDisable(GL_CULL_FACE);
		if(mode & OBJ3D_MODE_SMOOTH){
			glEnable(GL_LIGHTING);
			glEnable(GL_BLEND);
			glColor4fv(o->color);
			o->display(o->object,false,o->texture);
		}else{
			glColor4f(0.,0.,0.,1.);
			o->display(o->object,false,0);
			glColor4fv(o->color);
			glEnable(GL_LIGHTING);
			glEnable(GL_BLEND);
		}
	}else if(mode & OBJ3D_MODE_FILL){
		if(mode & OBJ3D_MODE_SMOOTH)				//Modo Smooth
			o->display(o->object,false,o->texture);
		else										//Modo Flat
			o->display(o->object,true,o->texture);
	}
	
	if(mode & OBJ3D_MODE_WIRE){					//Modo Wire
		glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
		glColor4f(1.,0.,0.,1.);
		o->display(o->object,true,0);
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	}
}

//Translacao em X
void object_trans_x(object * obj,short int sign){
	GLfloat offset=sign*0.1;
	GLfloat * matrix=matrix_create();
	matrix[3]+=offset;
	matrix_mult_trans(obj->matrix,matrix);
	matrix_delete(matrix);
}
//Translacao em Y
void object_trans_y(object * obj,short int sign){
	GLfloat offset=sign*0.1;
	GLfloat * matrix=matrix_create();
	matrix[7]+=offset;
	matrix_mult_trans(obj->matrix,matrix);
	matrix_delete(matrix);
}
//Translacao em Z
void object_trans_z(object * obj,short int sign){
	GLfloat offset=sign*0.1;
	GLfloat * matrix=matrix_create();
	matrix[11]+=offset;
	matrix_mult_trans(obj->matrix,matrix);
	matrix_delete(matrix);
}

//Rotacao no eixo X
void object_rot_x(object * obj,short int sign){
//	obj->rotate.x+=sign*10.0;
}
//Rotacao no eixo Y
void object_rot_y(object * obj,short int sign){
//	obj->rotate.y+=sign*10.0;
}
//Rotacao no eixo Z
void object_rot_z(object * obj,short int sign){
//	obj->rotate.z+=sign*10.0;
}

//Tamanho
void object_size(object * obj,short int sign){
	GLfloat offset=sign*0.1;
	GLfloat * matrix=matrix_create();
	matrix[0]+=offset;
	matrix[5]+=offset;
	matrix[10]+=offset;
	matrix_mult_trans(obj->matrix,matrix);
	matrix_delete(matrix);
}

//Escala em X
void object_scale_x(object * obj,short int sign){
	GLfloat offset=sign*0.1;
	GLfloat * matrix=matrix_create();
	matrix[0]+=offset;
	matrix_mult_trans(obj->matrix,matrix);
	matrix_delete(matrix);
}
//Escala em Y
void object_scale_y(object * obj,short int sign){
	GLfloat offset=sign*0.1;
	GLfloat * matrix=matrix_create();
	matrix[5]+=offset;
	matrix_mult_trans(obj->matrix,matrix);
	matrix_delete(matrix);
}
//Escala em Z
void object_scale_z(object * obj,short int sign){
	GLfloat offset=sign*0.1;
	GLfloat * matrix=matrix_create();
	matrix[10]+=offset;
	matrix_mult_trans(obj->matrix,matrix);
	matrix_delete(matrix);
}

//Seta Cor do Objeto
void object_set_color(object * obj,GLfloat r, GLfloat g, GLfloat b, GLfloat a){
	obj->color[0]=r;
	obj->color[1]=g;
	obj->color[2]=b;
	obj->color[3]=a;
}

//Seta Ambiente
void object_set_ambient(object * obj,GLfloat r, GLfloat g, GLfloat b, GLfloat a){
	obj->ambient[0]=r;
	obj->ambient[1]=g;
	obj->ambient[2]=b;
	obj->ambient[3]=a;
}

//Seta Difusa
void object_set_diffuse(object * obj,GLfloat r, GLfloat g, GLfloat b, GLfloat a){
	obj->diffuse[0]=r;
	obj->diffuse[1]=g;
	obj->diffuse[2]=b;
	obj->diffuse[3]=a;
}

//Seta Especular
void object_set_specular(object * obj,GLfloat r, GLfloat g, GLfloat b, GLfloat a){
	obj->specular[0]=r;
	obj->specular[1]=g;
	obj->specular[2]=b;
	obj->specular[3]=a;
}

//Seta Emissao
void object_set_emission(object * obj,GLfloat r, GLfloat g, GLfloat b, GLfloat a){
	obj->emission[0]=r;
	obj->emission[1]=g;
	obj->emission[2]=b;
	obj->emission[3]=a;
}

//Seta Brilho
void object_set_shininess(object * obj,GLfloat shininess){
	obj->shininess=shininess;
}
